// exe_backscatter.cpp

#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <list>

#include <quigon.h>

#ifdef MACRO_STK
#include "stk_para.h"
#include "stk_lidar.h"
#include "stk_lidar_io.h"
#endif	//MACRO_STK

#ifdef MACRO_YL
#include "stk_para.h"
#include "yl_lidar.h"
#include "yl_lidar_io.h"
#endif	//MACRO_YL

#include "basic_process.h"
#include "output_lidarpro.h"

using namespace std;
using namespace quigon;
using namespace boost::posix_time;

#ifdef MACRO_STK
typedef STK_Para Para;
typedef STK_Line Line; 
const string para_file = "../settings/stk_lidar_para.txt";
const string prefix = "stk";
#endif	//MACRO_STK

#ifdef MACRO_YL
typedef YL_Para Para;
typedef YL_Line Line;
const string para_file = "../settings/yl_lidar_para.txt";
const string prefix = "yl";
#endif	//MACRO_YL

int main(int argc, char *argv[])
{
	string start_t, end_t;
	double distance;
	if (argc < 4)
	{
		cout << "usage: test_backscatter yyyymmddThhmmss yyyymmddThhmmss distance" << endl;
		cout << "The capital 'T' in the 'iso time string' is optional" << endl;
		exit(0);
	}
	else
	{
		start_t = argv[1];
		end_t = argv[2];
		distance = atof(argv[3]);
	}

	// Check the date_time format, if not iso string, add 'T' into it.
	if (start_t[8] != 'T')
		start_t.insert(8, 1, 'T');
	if (end_t[8] != 'T')
		end_t.insert(8, 1, 'T');

	// Load lidar parameters
	cout << "Loading parameters" << endl;
	Para para(para_file);

	// find out how many bins do we need in the lines.
	int max_line_size = para.distance_i[distance] + 1;

	// Make a container.
	cout << "Making a container for the data." << endl;
	list<Line> container;
	Time_Serie cbh_serie;

	// import the data.
	cout << "Importing data..." << endl;
	import(
	        container,
	        from_iso_string(start_t),		// boost::posix_time::from_iso_string
	        from_iso_string(end_t),		// take care of the "T" in the string
	        para
	);

	cout << "Lines num: " << container.size() << endl;

	// Make a functor for data correction.
	Correction<Line, Para> corr(
	        para,
	        (Status::BACKGROUND |
	         Status::AFTERPULSE |
	         Status::DISTANCE   |
	         Status::OVERLAP    |
	         Status::ENERGY
	        ) ,
	        false
	);

	// Make a functor to fill the lowest blind range of lidar
	Fill_Lowest filler(para, 5);

	for (list<Line>::iterator i = container.begin();
	     i != container.end();
	     ++i)
	{
		i->resize(max_line_size);
		corr(*i);
		filler(*i);
		cbh_serie.add_entry(i->t(), (*i)["cbh1"]);
	}

	// fill time gaps.
	cout << "Filling time gap..." << endl;
	fill_time_gap(container);

	// On output
	string output_file_name_base = string("../output/") + prefix + "_"
 + start_t + "_" + end_t;
	string::iterator str_iter =
	        remove(output_file_name_base.begin(), output_file_name_base.end(), 'T');
	output_file_name_base.erase(str_iter, output_file_name_base.end());
	string output_file_name = output_file_name_base + ".backscat.txt";
	string cbh_file_name = output_file_name_base + ".bs_cbh1.txt";
	ofstream file(output_file_name.c_str());
	if (!file)
	{
		func_err("Cannot open file to write", output_file_name);
		return 1;
	}
	
	// Make a functor for data printing.
	Output_Lidarpro printer(file, para.zero_meter_index);

	cout << "Outputing data to: " << output_file_name << endl;
	for (list<Line>::iterator i = container.begin();
	     i != container.end();
	     ++i)
	{
		printer(*i);
	}
	cbh_serie.save(cbh_file_name);

	cout << "Task completed" << endl;
	return 0;
}

